package com.wyp.service.impl;


import com.wyp.controller.MSController;
import com.wyp.dao.MSOrderMapper;
import com.wyp.entity.MSOrder;
import com.wyp.service.MSGoodsService;
import com.wyp.service.OrderService;
import com.wyp.utils.md5.MD5Utils;
import com.wyp.utils.redis.RedisService;
import com.wyp.utils.redis.prekey.pre.MSKey;
import com.wyp.utils.redis.prekey.pre.OrderKey;
import com.wyp.utils.uuid.UUIDUtils;
import com.wyp.vo.GoodsVO;
import com.wyp.entity.OrderInfo;
import com.wyp.entity.User;
import com.wyp.service.MSService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import java.util.List;

/**
 * @author: Oliver
 */
@Service
public class MSServiceImpl implements MSService {

    @Autowired
    MSGoodsService MSGoodsService;
    @Autowired
    OrderService orderService;
    @Autowired
    MSOrderMapper MSOrderMapper;
    @Autowired
    RedisService redisService;
    /**
     * 运算符数组
     */
    private static char[] ops = new char[]{'+', '-', '*'};

    @Override
    @Transactional
    public OrderInfo MS(User user, GoodsVO goods) {
        boolean success = MSGoodsService.decrStock(goods);
        if (success) {
            //创建订单
            return orderService.createOrder(user, goods);
        } else {
            //说明数量已经没有了，秒杀结束
            setGoodsOver(goods.getId());
            return null;
        }
    }

    @Override
    public MSOrder getMSOrderByUserIdAndGoodsId(User user, GoodsVO goods) {
        Long userId = user.getId();
        Long goodsId = goods.getId();
        //从缓存中取数据 --r数据库中取数据
        MSOrder MSOrder = redisService.get(OrderKey.MS_ORDER_INFO, "" + userId + "_" + goodsId, MSOrder.class);
        return MSOrder;
    }

    @Override
    public long getMSResult(Long userId, long goodsId) {
        User user = new User();
        user.setId(userId);
        GoodsVO goodsVO = new GoodsVO();
        goodsVO.setId(goodsId);
        OrderInfo order = orderService.getOrderByUserIdAndGoodsId(user, goodsVO);
        if (order != null) {//秒杀成功
            return order.getId();
        } else {
            boolean isOver = getGoodsOver(goodsId);
            if (!isOver) {//此商品的秒杀还没结束，返回处理中
                //获取所有的秒杀订单, 判断订单数量和参与秒杀的商品数量 防止数量已经-1但是订单还在生成中，获取不到订单信息而导致显示错误。
                // （用户看到自己秒杀失败，但是过一会查询订单发现秒杀成功）
                return 0;
            } else {
                List<MSOrder> orders = orderService.getAllMSOrdersByGoodsId(goodsId);
                if (orders == null || orders.size() < MSController.getGoodsStockOriginal(goodsId)) {
                    return 0;//订单还在生成中
                } else {//判断是否有此用户的订单
                    MSOrder userOrder = get(orders, userId);
                    if (userOrder != null) {//如果有，则说明秒杀成功
                        return userOrder.getOrderId();
                    } else {//秒杀失败
                        return -1;
                    }
                }
            }
        }
    }

    /**
     * 获取该列表订单中指定用户的订单
     *
     * @param orders
     * @param userId
     * @return
     */
    private MSOrder get(List<MSOrder> orders, Long userId) {
        if (orders == null || orders.size() <= 0) {
            return null;
        }
        for (MSOrder order : orders) {
            if (order.getUserId().equals(userId)) {
                return order;
            }
        }
        return null;
    }

    @Override
    public String createPath(User user, Long goodsId) {
        if (user == null || goodsId <= 0) {
            return null;
        }
        String str = MD5Utils.md5(UUIDUtils.getUUID() + "123456");
        //存放redis
        redisService.set(MSKey.MS_PATH_REALLY, user.getId() + "_" + goodsId, str);
        return str;
    }

    /**
     * 校验秒杀地址是否正确
     *
     * @param user    用户
     * @param goodsId 商品id
     * @param path    前端传过来path
     * @return
     */
    @Override
    public boolean checkPath(User user, Long goodsId, String path) {
        if (user == null || goodsId <= 0 || path == null) {
            return false;
        }
        //获取redis中存放的path进行比较
        String redisPath = redisService.get(MSKey.MS_PATH_REALLY, user.getId() + "_" + goodsId, String.class);
        return path.equals(redisPath);

    }

    /**
     * 创建验证码图片
     *
     * @param user
     * @param goodsId
     * @return
     */
    @Override
    public BufferedImage createVerifyCode(User user, Long goodsId) {
        if (user == null || goodsId <= 0) {
            return null;
        }
        int width = 80;
        int height = 32;
        //create the image
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        // set the background color
        g.setColor(new Color(0xDCDCDC));
        g.fillRect(0, 0, width, height);
        // draw the border
        g.setColor(Color.black);
        g.drawRect(0, 0, width - 1, height - 1);
        // create a random instance to generate the codes
        Random rdm = new Random();
        // make some confusion
        for (int i = 0; i < 50; i++) {
            int x = rdm.nextInt(width);
            int y = rdm.nextInt(height);
            g.drawOval(x, y, 0, 0);
        }
        // generate a random code
        String verifyCode = generateVerifyCode(rdm);
        g.setColor(new Color(0, 100, 0));
        g.setFont(new Font("Candara", Font.BOLD, 24));
        g.drawString(verifyCode, 8, 24);
        g.dispose();
        int rnd = calc(verifyCode);

        //把图片上表达式计算结果存到redis中
        redisService.set(MSKey.MS_VERIFY_CODE, user.getId() + "," + goodsId, rnd);
        //输出图片
        return image;
    }

    /**
     * 校验验证码
     *
     * @param user
     * @param goodsId
     * @param verifyCode
     * @return
     */
    @Override
    public boolean checkVerifyCode(User user, Long goodsId, Integer verifyCode) {
        if (user == null || goodsId <= 0) {
            return false;
        }
        Integer codeOld = redisService.get(MSKey.MS_VERIFY_CODE, user.getId() + "," + goodsId, Integer.class);
        if (codeOld == null || codeOld - verifyCode != 0) {
            return false;
        }
        redisService.delete(MSKey.MS_VERIFY_CODE, user.getId() + "," + goodsId);
        return true;
    }

    private int calc(String exp) {
        try {
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("JavaScript");
            return (Integer) engine.eval(exp);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * + - *  随机产生运算字符串
     */
    private String generateVerifyCode(Random rdm) {
        int num1 = rdm.nextInt(10);
        int num2 = rdm.nextInt(10);
        int num3 = rdm.nextInt(10);
        char op1 = ops[rdm.nextInt(3)];
        char op2 = ops[rdm.nextInt(3)];
        String exp = "" + num1 + op1 + num2 + op2 + num3;
        return exp;
    }

    /**
     * 用来判断是否秒杀结束
     *
     * @param goodsId
     */
    private void setGoodsOver(Long goodsId) {
        redisService.set(MSKey.IS_GOODS_OVER, "" + goodsId, true);
    }

    private boolean getGoodsOver(long goodsId) {
        return redisService.exists(MSKey.IS_GOODS_OVER, "" + goodsId);
    }
}
